package com.googlecode.jsqlconverter.definition.create.table;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.googlecode.jsqlconverter.definition.Name;
import com.googlecode.jsqlconverter.definition.Statement;
import com.googlecode.jsqlconverter.definition.create.table.constraint.CompoundForeignKeyConstraint;
import com.googlecode.jsqlconverter.definition.create.table.constraint.KeyConstraint;

// TODO: support non-unique keys, compound or otherwise
public class CreateTable extends Statement {
	private Name tableName;
	private ArrayList<Column> columns = new ArrayList<Column>();
	private ArrayList<TableOption> options = new ArrayList<TableOption>();
	private ArrayList<KeyConstraint> compoundUniqueKeys = new ArrayList<KeyConstraint>();
	private ArrayList<CompoundForeignKeyConstraint> compoundForeignKeys = new ArrayList<CompoundForeignKeyConstraint>();
	private KeyConstraint primaryKey = null;

	public CreateTable(Name tableName) {
		this.tableName = tableName;
	}

	// getters
	public Name getName() {
		return tableName;
	}

	public Column[] getColumns() {
		return columns.toArray(new Column[columns.size()]);
	}

	public Column getColumn(int index) {
		return columns.get(index);
	}

	public Column getColumn(String name) {
		for (Column column : columns) {
			if (column.getName().getObjectName().equals(name)) {
				return column;
			}
		}

		return null;
	}

	public int getColumnCount() {
		return columns.size();
	}

	public TableOption[] getTableOptions() {
		return options.toArray(new TableOption[options.size()]);
	}

	public KeyConstraint getPrimaryCompoundKeyConstraint() {
		return primaryKey;
	}

	public KeyConstraint[] getUniqueCompoundKeyConstraint() {
		return compoundUniqueKeys.toArray(new KeyConstraint[compoundUniqueKeys.size()]);
	}

	public CompoundForeignKeyConstraint[] getCompoundForeignKeyConstraints() {
		return compoundForeignKeys.toArray(new CompoundForeignKeyConstraint[compoundForeignKeys.size()]);
	}

	public boolean containsOption(TableOption option) {
		return options.contains(option);
	}

	// setters
	public void setName(Name tableName) {
		this.tableName = tableName;
	}

	public void setColumn(int index, Column column) {
		columns.set(index, column);
	}

	public void setPrimaryCompoundKeyConstraint(KeyConstraint keyConstraint) {
		primaryKey = keyConstraint;
	}

	// adders
	public void addColumn(Column column) {
		columns.add(column);
	}

	public void addOption(TableOption option) {
		options.add(option);
	}

	public void addUniqueCompoundKeyConstraint(KeyConstraint keyConstraint) {
		compoundUniqueKeys.add(keyConstraint);
	}

	public void addCompoundForeignKeyConstraint(CompoundForeignKeyConstraint keyConstraint) {
		compoundForeignKeys.add(keyConstraint);
	}

	// removers
	public void removeColumn(Column column) {
		columns.remove(column);
	}


	
	public static List<CreateTable> OrderByDependencies(Collection<CreateTable> tables) {
		List<CreateTable> ordered=new ArrayList<CreateTable>();
		Collection<CreateTable> unordered=new ArrayList<CreateTable>(tables);
		Set<String> orderednames=new HashSet<String>();
		while (!unordered.isEmpty()) {
			Collection<CreateTable> done=new ArrayList<CreateTable>();
			for (CreateTable c : unordered)
				if (dependsOnTables(c,orderednames)) {
					done.add(c);
					orderednames.add(c.getName().getObjectName());
					ordered.add(c);
				}
			unordered.removeAll(done);
		}
		return ordered;
		
	}
	private static boolean dependsOnTables(CreateTable c, Set<String> orderednames) {
		for (Column column : c.getColumns()) {
			if (column.getForeignKeyConstraint() != null) {
				if (!column.getForeignKeyConstraint().getTableName().getObjectName().
						equals(c.getName().getObjectName()) &&
					!orderednames.contains(column.getForeignKeyConstraint().getTableName().getObjectName())) 
					return false;
				
			}
		}
		return true;
	}

	
}
